package com.flca.frw.zk.util;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zkoss.zk.ui.AbstractComponent;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlMacroComponent;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zul.Combobox;
import org.zkoss.zul.Comboitem;
import org.zkoss.zul.Constraint;
import org.zkoss.zul.Datebox;
import org.zkoss.zul.Decimalbox;
import org.zkoss.zul.Intbox;
import org.zkoss.zul.Label;
import org.zkoss.zul.ListModel;
import org.zkoss.zul.Longbox;
import org.zkoss.zul.Radio;
import org.zkoss.zul.Radiogroup;
import org.zkoss.zul.SimpleConstraint;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Window;
import org.zkoss.zul.impl.InputElement;
import org.zkoss.zul.impl.LabelElement;

import com.flca.frw.beanutils.MethodHelper;
import com.flca.frw.util.Parameters;
import com.flca.frw.util.TransformUtils;
import com.flca.frw.zk.comp.IFormItem;
import com.flca.frw.zk.comp.ManyToOneCtrl;
import com.flca.frw.zk.comp.OneToManyCtrl;
import com.flca.frw.zk.validate.ValidateCombobox;

public class WindowHelper {

	private Component component;

	private TransformUtils tu = TransformUtils.getInstance();

	private static Logger logger = LoggerFactory.getLogger(WindowHelper.class);


	public WindowHelper(Component aComponent) {
		component = aComponent;
	}

	/**
	 * Shortcut to update either the field from the model or vice versa. This is
	 * indicated by the last boolean arg, true: model->view false: view->model
	 * 
	 * @param aFieldname
	 *           the name of ZK field
	 * @param aObject
	 *           the source or target object
	 * @param aPropertyname
	 *           the property name from the aTarget
	 * @param aUpdateView
	 */
	public void updateField(String aFieldname, Object aObject, String aPropertyname, boolean aUpdateView) {
		Component comp = getComponent(aFieldname);

		try {
			if (aUpdateView) {
				updateToView(comp, aObject, aPropertyname);
			} else {
				updateToModel(comp, aObject, aPropertyname);
			}
		} catch (Exception e) {
			String msg = "Error in updateField() comp=" + comp + " obj=" + aObject + " prop=" + aPropertyname + " updateView=" + aUpdateView;
			logger.error(msg, e);
			e.printStackTrace();
		}
	}

	private void updateToView(Component aTargetComp, Object aSourceObject, String aPropertyName) throws Exception {
		Method getter = MethodHelper.getGetter(aSourceObject, aPropertyName);
		if (getter != null) {
			Object value = getter.invoke(aSourceObject, new Object[] {});

			if (aTargetComp instanceof Textbox) {
				((Textbox) aTargetComp).setValue(tu.object2String(value));
			} else if (aTargetComp instanceof Decimalbox) {
				((Decimalbox) aTargetComp).setValue(tu.object2BigDecimal(value));
			} else if (aTargetComp instanceof Intbox) {
				((Intbox) aTargetComp).setValue(tu.object2Integer(value));
			} else if (aTargetComp instanceof Longbox) {
				((Longbox) aTargetComp).setValue(tu.object2Long(value));
			} else if (aTargetComp instanceof Datebox) {
				((Datebox) aTargetComp).setValue(tu.object2Date(value));
			} else if (aTargetComp instanceof Label) {
				((Label) aTargetComp).setValue(tu.object2String(value));
			} else if (aTargetComp instanceof Radiogroup) {
				RadioGroupHelper.setSelectedItem((Radiogroup) aTargetComp, value);
			} else if (isFormItem(aTargetComp)) {
				getFormItem(aTargetComp).updateView(value);
			} else {
				Alert.show("no valid component found  " + aTargetComp);
			}
		} else {
			Alert.show("no getter found for " + aPropertyName);
		}
	}

	private void updateToModel(Component aSourceComp, Object aTargetObject, String aPropertyName) throws Exception {
		Method setter = MethodHelper.getSetter(aTargetObject, aPropertyName);
		if (setter != null) {
			if (aSourceComp instanceof InputElement) {
				Object value = ((InputElement) aSourceComp).getRawValue();
				if (value != null) {
					setValue(value, setter, aTargetObject);
				} else {
					setter.invoke(aTargetObject, new Object[] { null });
				}
			} else if (isFormItem(aSourceComp)) {
				IFormItem formitem = getFormItem(aSourceComp);
				formitem.updateModel(aTargetObject, setter);
			}
		} else {
			throw new Exception("no setter found for " + aPropertyName);
		}
	}

	public void setValue(Object aSourceValue, Method setter, Object aTargetObject) throws Exception {
		Class<?> paramTypes[] = setter.getParameterTypes();
		Class<?> targetCls = paramTypes[0];
		Class<?> sourceCls = aSourceValue.getClass();

		if (sourceCls.equals(targetCls)) {
			setter.invoke(aTargetObject, new Object[] { aSourceValue });
		} else {
			setTheValue(aSourceValue, aTargetObject, setter, targetCls);
		}
	}

	private void setTheValue(Object aSourceValue, Object aTargetObject, Method setter, Class<?> aTargetClass) throws Exception {
		if (aSourceValue instanceof String) {
			setTheValue((String) aSourceValue, aTargetObject, setter, aTargetClass);
		} else if (aSourceValue instanceof Integer) {
			setTheValue((Integer) aSourceValue, aTargetObject, setter, aTargetClass);
		} else {
			logger.error("setTheValue() is unable to convert a " + aSourceValue.getClass() + " to a " + aTargetClass);
		}
	}

	private void setTheValue(String aSourceValue, Object aTargetObject, Method setter, Class<?> aTargetClass) throws Exception {
		if (Integer.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.string2Integer(aSourceValue));
		} else if (int.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.string2int(aSourceValue));
		} else if (Long.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.string2Long(aSourceValue));
		} else if (long.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.string2long(aSourceValue));
		} else if (BigDecimal.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.string2BigDecimal(aSourceValue));
		} else {
			logger.error("setTheValue() is unable to convert a String to a " + aTargetClass);
		}
	}

	private void setTheValue(Integer aSourceValue, Object aTargetObject, Method setter, Class<?> aTargetClass) throws Exception {
		if (String.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.integer2String(aSourceValue));
		} else if (int.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, aSourceValue.intValue());
		} else if (BigDecimal.class.equals(aTargetClass)) {
			setter.invoke(aTargetObject, tu.integer2BigDecimal(aSourceValue));
		} else {
			logger.error("setTheValue() is unable to convert an Integer to a " + aTargetClass);
		}
	}

	public void setComboBox(String aFieldname, Object aValue, List<String> aStringList) {
		ListModel listmodel = ListModelHelper.makeListModel(aStringList, true);

		setComboBox(aFieldname, aValue, listmodel);
	}

	public void setComboBox(String aFieldname, Object aValue, ListModel aListModel) {
		Component comp = getComponent(aFieldname);

		if (comp instanceof Combobox) {
			Combobox cbox = (Combobox) comp;
			fillComboBox(aListModel, cbox);
			ListModelHelper.setSelectedItem(cbox, aValue);
		} else {
			throw new RuntimeException("targetcomp is not a ComboBox");
		}
	}

	public void updateComboBox(String aFieldname, Object aObject, String aPropertyname, List<String> aListModel, boolean aUpdateView) {
		ListModel listmodel = ListModelHelper.makeListModel(aListModel, true);
		updateComboBox(aFieldname, aObject, aPropertyname, listmodel, aUpdateView);
	}

	/**
	 * This will fill the combobox with the given <b>Enum</b> property
	 * 
	 * @param aFieldname
	 * @param aObject
	 * @param aPropertyname
	 *           this must be an valid enum property
	 * @param aUpdateView
	 */
	public void updateComboBox(String aFieldname, Object aObject, String aPropertyname, boolean aUpdateView) {
		if (aObject != null && aPropertyname != null) {
			Method getter = MethodHelper.getGetter(aObject, aPropertyname);
			if (getter != null) {
				Class<?> rettyp = getter.getReturnType();
				ListModel enumitems = ListModelHelper.makeListModel(rettyp, true);
				updateComboBox(aFieldname, aObject, aPropertyname, enumitems, aUpdateView);
			} else {
				logger.warn("no getter for : " + aPropertyname + " in " + aObject.getClass().getSimpleName());
			}
		}
	}

	public void updateComboBox(String aFieldname, Object aObject, String aPropertyname, ListModel aListModel, boolean aUpdateView) {
		Component comp = getComponent(aFieldname);

		try {
			if (aUpdateView) {
				updateToComboBox(comp, aObject, aPropertyname, aListModel);
			} else {
				updateFromComboBox(comp, aObject, aPropertyname);
			}
		} catch (Exception e) {
			String msg = "Error in updateComboBox() comp=" + comp + " obj=" + aObject + " prop=" + aPropertyname + " updateView="
					+ aUpdateView;
			logger.error(msg, e);
			e.printStackTrace();
		}
	}

	public void updateToComboBox(Component aTargetComp, Object aObject, String aPropertyName, ListModel aListModel) throws Exception {
		if (aTargetComp instanceof Combobox && aListModel != null && aListModel.getSize() > 0) {

			Combobox cbox = (Combobox) aTargetComp;
			fillComboBox(aListModel, cbox);

			if (aObject != null && aPropertyName != null) {
				Method getter = MethodHelper.getGetter(aObject, aPropertyName);
				if (getter != null) {
					Object currValue = getter.invoke(aObject, new Object[] {});
					ListModelHelper.setSelectedItem(cbox, currValue);
				} else {
					logger.warn("no getter for : " + aPropertyName + " in " + aObject.getClass().getSimpleName());
				}
			} else {
				cbox.setSelectedIndex(0);
				// log.error("updateToComboBox source object and/or property name is null");
			}
		} else if (isFormItem(aTargetComp) && aListModel != null && aListModel.getSize() > 0) {
			IFormItem iformitem = getFormItem(aTargetComp);
			Window formitem = (Window) iformitem;

			Combobox cbox = (Combobox) formitem.getFellow("idInput");
			fillComboBox(aListModel, cbox);

			if (aObject != null && aPropertyName != null) {
				Method getter = MethodHelper.getGetter(aObject, aPropertyName);
				if (getter != null) {
					Object currValue = getter.invoke(aObject, new Object[] {});
					iformitem.updateView(currValue);
				} else {
					logger.warn("no getter for : " + aPropertyName + " in " + aObject.getClass().getSimpleName());
				}
			} else {
				cbox.setSelectedIndex(0);
				// log.error("updateToComboBox source object and/or property name is null");
			}

		} else {
			throw new Exception("targetcomp is not a ComboBox");
		}
	}

	private void updateFromComboBox(Component aSourceComp, Object aObject, String aPropertyName) throws Exception {
		Method setter = null;
		if (aObject != null && aPropertyName != null) {
			setter = MethodHelper.getSetter(aObject, aPropertyName);
			if (setter == null) {
				Alert.show("no setter found for " + aPropertyName);
				return;
			}
		}

		if (aSourceComp instanceof Combobox) {
			Combobox cbox = (Combobox) aSourceComp;
			Comboitem value = cbox.getSelectedItem();

			Object val = value.getValue();
			setter.invoke(aObject, new Object[] { val });
		} else if (isFormItem(aSourceComp)) {
			getFormItem(aSourceComp).updateModel(aObject, setter);
		} else {
			throw new Exception("targetcomp is not a ComboBox");
		}
	}

	private void fillComboBox(ListModel aListModel, Combobox cbox) {
		if (cbox.getItemCount() == 0) {
			for (int i = 0; i < aListModel.getSize(); i++) {
				Object o = aListModel.getElementAt(i);
				if (o instanceof ListItem) {
					ListItem listdata = (ListItem) o;
					Comboitem cbItem = cbox.appendItem(listdata.getLabel());
					cbItem.setValue(listdata.getValue());
				} else {
					Comboitem cbItem = cbox.appendItem(o.toString());
					cbItem.setValue(o);
				}
			}
		}
	}

	/**
	 * Convenience wrapper for getComponent(String,Component)
	 * 
	 * @param aCompname
	 * @return
	 */
	public Component getComponent(String aCompname) {
		return getComponent(aCompname, component);
	}

	/**
	 * gets a component relative to the idSpace of parent.
	 * 
	 * @param aCompname
	 * @param parent
	 * @return
	 */
	public Component getComponent(String aCompname, Component parent) {
		Component result = null;

		if (aCompname.indexOf('/') >= 0) {
			int n = aCompname.indexOf('/');
			String s1 = aCompname.substring(0, n);
			String s2 = aCompname.substring(n + 1);
			Component c1 = parent.getFellow(s1);
			if (c1 != null && !StringUtils.isEmpty(s2)) {
				result = getComponent(s2, c1);
			}
		} else {
			if (parent instanceof HtmlMacroComponent && parent.getFirstChild() != null) {
				return getComponent(aCompname, parent.getFirstChild());
			} else {
				result = parent.getFellow(aCompname);
			}
		}

		if (result != null) {
			return result;
		} else {
			throw new RuntimeException("Component " + aCompname + " not found");
		}
	}

	public void validateNotEmpty(String aFieldname) {
		if (!skipValidation()) {
			SimpleConstraint sc = SimpleConstraint.getInstance("no empty");

			Component comp = getComponent(aFieldname);
			if (comp instanceof InputElement) {
				InputElement elem = (InputElement) comp;

				if (elem == null || !isCompVisible(elem)) {
					return;
				}

				elem.setConstraint(sc);

				triggerConstraint(aFieldname, elem);
			} else if (isFormItem(comp)) {
				IFormItem formitem = getFormItem(comp);
				formitem.validate(sc);
			}
		}
	}

	public boolean validate(String aFieldname, Constraint aConstraint) {
		if (!skipValidation()) {
			Component comp = getComponent(aFieldname);
			if (comp instanceof InputElement) {
				InputElement elem = (InputElement) comp;

				if (!isCompVisible(elem)) {
					return true;
				}

				elem.setConstraint(aConstraint);

				triggerConstraint(aFieldname, elem);
			} else if (isFormItem(comp)) {
				IFormItem formitem = getFormItem(comp);
				formitem.validate(aConstraint);
			}
		}
		return true;
	}

	public void validateRadioGroupNotEmpty(String aFieldname) {
		if (!skipValidation()) {
			Component elem = (Component) getComponent(aFieldname);
			if (isCompVisible(elem)) {
				triggerConstraint(aFieldname, elem);
			}
		}
	}

	public void validateComboBoxNotEmpty(String aFieldname) {
		if (!skipValidation()) {
			InputElement elem = (InputElement) getComponent(aFieldname);

			if (!isCompVisible(elem)) {
				return;
			}

			elem.setConstraint(new ValidateCombobox());

			triggerConstraint(aFieldname, elem);
		}
	}

	private boolean skipValidation() {
		boolean result = false;

		String s = System.getProperty(Parameters.SKIP_VALIDATION);
		result = (s != null && s.toUpperCase().startsWith("T"));

		return result;
	}

	@SuppressWarnings("unchecked")
	private void triggerConstraint(String aFieldname, Component elem) {
		if (elem != null) {
			if (elem instanceof Combobox) {
				Comboitem cbItem = ((Combobox) elem).getSelectedItem();
				if (cbItem == null || cbItem.getValue() == null) {
					throw new WrongValueException(elem, Labels.getLabel("missingRequiredChoiceValue"));
				}
				((Combobox) elem).getValue(); // force validation
				return;
			}

			else if (elem instanceof Radiogroup) {
				Radiogroup rg = (Radiogroup) elem;

				Collection<AbstractComponent> list = rg.getChildren();
				rg.getFellows();
				for (AbstractComponent comp : list) {
					if (((Radio) comp).isChecked()) {
						return;
					}
				}
				throw new WrongValueException(elem, Labels.getLabel("missingRequiredChoiceValue"));
			} else if (elem instanceof Textbox) {
				((Textbox) elem).getValue(); // force validation
				return;
			} else if (elem instanceof Decimalbox) {
				((Decimalbox) elem).getValue(); // force validation
				return;
			} else if (elem instanceof Datebox) {
				((Datebox) elem).getValue(); // force validation
				return;
			} else if (elem instanceof Intbox) {
				((Intbox) elem).getValue(); // force validation
				return;
			}
			if (elem instanceof Longbox) {
				((Longbox) elem).getValue();
				return;
			}
		}

		throw new RuntimeException("No component found in validateNotEmpty for " + aFieldname);
	}

	public boolean isCompVisible(Component aElem) {
		if (!aElem.isVisible()) {
			return false;
		} else {
			if (aElem.getParent() == null) {
				return true;
			} else {
				return isCompVisible(aElem.getParent());
			}
		}
	}

	/**
	 * This will replace the label of all Label Button and ToolbarButton's if the
	 * id corresponds to an id in label properties file (@see Labels) Note a
	 * Button of ToolbarButton must also have a dummy label (because these work
	 * with images)
	 * 
	 * @param aElem
	 */
	@SuppressWarnings("unchecked")
	public void updateLabels(Component aElem) {
		List<Component> children = aElem.getChildren();
		for (Component c : children) {
			if (c instanceof Label) {
				if (c.getId() != null) {
					String value = getLabel(c.getId());

					if (value != null && !value.equals(c.getId())) {
						((Label) c).setValue(value);
					}
				}
			} else if (c instanceof LabelElement) {
				// nb only if the button has a dummy label
				LabelElement labelElem = (LabelElement) c;
				if (labelElem.getId() != null && labelElem.getLabel() != null) {
					String value = getLabel(c.getId());
					if (value != null && labelElem.getLabel() != null && !value.equals(c.getId())) {
						labelElem.setLabel(value);
					}
				}
			} else if (c.getChildren() != null && c.getChildren().size() > 0) {
				updateLabels(c);
			}
		}
	}

	private String getLabel(String aKey) {
		return Labels.getLabel(aKey);

	}

	/**
	 * This will update the radiogroup with the given <b>Enum</b> property
	 * 
	 * @param aFieldname
	 * @param aObject
	 * @param aPropertyname
	 *           this must be an valid enum property
	 * @param aUpdateView
	 */
	public void updateRadioGroup(String aFieldname, Object aObject, String aPropertyname, boolean aUpdateView) {
		if (aObject != null && aPropertyname != null) {
			ListModel listmodel = ListModelHelper.makeListModel(aObject, aPropertyname);
			updateRadioGroup(aFieldname, aObject, aPropertyname, listmodel, aUpdateView);
		}
	}

	public void updateRadioGroup(String aFieldname, Object aObject, String aPropertyname, ListModel aListModel, boolean aUpdateView) {
		Component comp = getComponent(aFieldname);

		try {
			if (aUpdateView) {
				updateToRadioGoup(comp, aObject, aPropertyname, aListModel);
			} else {
				updateFromRadioGoup(comp, aObject, aPropertyname);
			}
		} catch (Exception e) {
			String msg = "Error in updateComboBox() comp=" + comp + " obj=" + aObject + " prop=" + aPropertyname + " updateView="
					+ aUpdateView;
			logger.error(msg, e);
			e.printStackTrace();
		}
	}

	public void updateToRadioGoup(Component aSourceComp, Object aObject, String aPropertyName, ListModel aListModel) throws Exception {
		if (aSourceComp instanceof Radiogroup && aListModel != null && aListModel.getSize() > 0) {

			Radiogroup radiogrp = (Radiogroup) aSourceComp;
			fillRadioGroup(aListModel, radiogrp);

			if (aObject != null && aPropertyName != null) {
				Method getter = MethodHelper.getGetter(aObject, aPropertyName);
				if (getter != null) {
					Object currValue = getter.invoke(aObject, new Object[] {});
					setSelectedRadioGroupItem(radiogrp, currValue);
				} else {
					logger.warn("no getter for : " + aPropertyName + " in " + aObject.getClass().getSimpleName());
				}
			} else {
				radiogrp.setSelectedIndex(0);
				// log.error("updateToComboBox source object and/or property name is null");
			}
		} else {
			throw new Exception("targetcomp is not a ComboBox");
		}
	}

	private void updateFromRadioGoup(Component aTargetComp, Object aObject, String aPropertyName) throws Exception {
		if (aTargetComp instanceof Radiogroup) {
			Radiogroup radiogrp = (Radiogroup) aTargetComp;
			Radio radio = radiogrp.getSelectedItem();

			if (radio != null && aObject != null && aPropertyName != null) {
				Method setter = MethodHelper.getSetter(aObject, aPropertyName);
				if (setter != null) {
					Object val = radio.getAttribute("val");
					setter.invoke(aObject, new Object[] { val });
				}
			} else {
				// throw new
				// Exception("source object and/or property name is null");
			}
		} else {
			throw new Exception("targetcomp is not a ComboBox");
		}
	}

	private void fillRadioGroup(ListModel aListModel, Radiogroup radiogrp) {
		if (radiogrp.getItemCount() == 0) {
			for (int i = 0; i < aListModel.getSize(); i++) {
				Object o = aListModel.getElementAt(i);
				if (o instanceof ListItem) {
					ListItem listdata = (ListItem) o;
					Radio radio = new Radio();
					radio.setLabel(listdata.getLabel());
					radio.setAttribute("val", listdata.getValue());
					radiogrp.appendChild(radio);
				} else {
					radiogrp.appendItem(o.toString(), o.toString());
				}
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void setSelectedRadioGroupItem(Radiogroup aRadioGrp, Object aValue) {
		if (aValue != null) {
			String value = aValue.toString();
			List<Radio> items = aRadioGrp.getChildren();
			for (Radio radio : items) {
				if (value.equals(radio.getValue()) || value.equals(radio.getLabel())) {
					aRadioGrp.setSelectedItem(radio);
					return;
				} else {
					Object radioValue = radio.getAttribute("val");
					if (aValue.equals(radioValue)) {
						aRadioGrp.setSelectedItem(radio);
						return;
					}
				}
			}
		} else {
			aRadioGrp.setSelectedIndex(-1);
		}
	}

	public boolean isFormItem(Component aComp) {
		return aComp != null && aComp.getFirstChild() != null && aComp.getFirstChild() instanceof IFormItem;
	}

	public IFormItem getFormItem(Component aComp) {
		return (IFormItem) aComp.getFirstChild();
	}

	public void updateManyToOne(ManyToOneCtrl aCtrl, Object aObject, String aPropertyname, boolean aUpdateView) {
		try {
			if (aUpdateView) {
				updManyToOneToView(aCtrl, aObject, aPropertyname);
			} else {
				updManyToOneToModel(aCtrl, aObject, aPropertyname);
			}
		} catch (Exception e) {
			String msg = "Error in updateField() comp=" + aCtrl + " obj=" + aObject + " prop=" + aPropertyname;
			;
			logger.error(msg, e);
			e.printStackTrace();
		}
	}

	private void updManyToOneToView(ManyToOneCtrl aTargetComp, Object aSourceObject, String aPropertyName) throws Exception {
		Method getter = MethodHelper.getGetter(aSourceObject, aPropertyName);
		if (getter != null) {
			Object value = getter.invoke(aSourceObject, new Object[] {});
			aTargetComp.updateView(value);
		}
	}

	private void updManyToOneToModel(ManyToOneCtrl aSourceComp, Object aTargetObject, String aPropertyName) throws Exception {
		Method setter = MethodHelper.getSetter(aTargetObject, aPropertyName);
		if (setter != null) {
			Object value = aSourceComp.getValue();
			if (value != null) {
				setValue(value, setter, aTargetObject);
			} else {
				setter.invoke(aTargetObject, new Object[] { null });
			}
		}
	}

	public void updateOneToMany(OneToManyCtrl aCtrl, Object aObject, String aPropertyname, boolean aUpdateView) {
		try {
			if (aUpdateView) {
				updOneToManyToView(aCtrl, aObject, aPropertyname);
			} else {
				updOneToManyToModel(aCtrl, aObject, aPropertyname);
			}
		} catch (Exception e) {
			String msg = "Error in updateField() comp=" + aCtrl + " obj=" + aObject + " prop=" + aPropertyname;
			;
			logger.error(msg, e);
			e.printStackTrace();
		}
	}

	private void updOneToManyToView(OneToManyCtrl aTargetComp, Object aSourceObject, String aPropertyName) throws Exception {
		Method getter = MethodHelper.getGetter(aSourceObject, aPropertyName);
		if (getter != null) {
			Object value = getter.invoke(aSourceObject, new Object[] {});
			aTargetComp.updateView(value);
		}
	}

	private void updOneToManyToModel(OneToManyCtrl aSourceComp, Object aTargetObject, String aPropertyName) throws Exception {
		Method setter = MethodHelper.getSetter(aTargetObject, aPropertyName);
		if (setter != null) {
			Object value = aSourceComp.getItems();
			if (value != null) {
				setValue(value, setter, aTargetObject);
			} else {
				setter.invoke(aTargetObject, new Object[] { null });
			}
		}
	}

	public OneToManyCtrl getOneToManyCtrl(String aPropertyName) {
		Component c = getComponent(aPropertyName);
		if (c != null && c.getFirstChild() != null && c.getFirstChild() instanceof OneToManyCtrl) {
			return (OneToManyCtrl) c.getFirstChild();
		} else {
			Alert.show(aPropertyName + " not a OneToManyCtrl");
			return null;
		}
	}

	public ManyToOneCtrl getManyToOneCtrl(String aPropertyName) {
		Component c = getComponent(aPropertyName);
		if (c != null && c.getFirstChild() != null && c.getFirstChild() instanceof ManyToOneCtrl) {
			return (ManyToOneCtrl) c.getFirstChild();
		} else {
			Alert.show(aPropertyName + " not a OneToManyCtrl");
			return null;
		}
	}

	public void clearComponent(Component aComp) {
		if (aComp != null) {
			while (aComp.getFirstChild() != null) {
				aComp.removeChild(aComp.getFirstChild());
			}
		}
	}
}
